﻿// Ulteriori informazioni su F# all'indirizzo http://fsharp.net
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open Microsoft.FSharp.Quotations.DerivedPatterns



let println expr = 
    let rec print expr = 
        match expr with
            | Application (expr1, expr2) ->
                //Function Application
                print expr1
                printf " "
                print expr2
            | SpecificCall <@@ (+) @@> (_, _, exprList) ->
                //Matches call to (+). Must appear before Call pattern
                print exprList.Head
                printf " + "
                print exprList.Tail.Head
            | Call (exprOpt, methodInfo, exprList) ->
                //Method or module function call
                match exprOpt with
                    | Some expres -> print expres
                    | None -> printf "%s" methodInfo.DeclaringType.Name
                printf ".%s("methodInfo.Name
                if exprList.IsEmpty then    
                    printf ")"
                else                        
                    print exprList.Head
                    for expression in exprList.Tail do
                        printf ","
                        print expression
                        printf ")"
            | Int32 (n) ->
                printf "%d" n
            | Lambda (param, body) ->
                //Lambda expression
                printf "fun (%s,%s) -> " param.Name (param.Type.ToString())
                print body
            | Let (var, expr1, expr2) ->
                //Let binding
                if var.IsMutable then 
                    printf "let mutable %s = " var.Name
                else
                    printf "let %s = " var.Name
                print expr1
                printf " in "
                print expr2
            | PropertyGet (_, propOrValInfo, _) ->
                printf "%s" propOrValInfo.Name
            | String (str) ->
                printf "%s" str
            | Value (value, typ) ->
                printf "%s" (value.ToString())
            | Var (var) ->
                printf "%s" var.Name
            | _ ->
                printf "%s" (expr.ToString())
    in
    print expr
    printfn ""



let a = 2

let exprLambda = <@ fun x -> x + 1 @>
let exprCall = <@ a + 1 @>

let p =     
        <@
            let f x = x + 10
            f 20
        @>


println exprLambda
println exprCall
println p

//<@1@>
//
//<@@1@@>
//
//
//Expr.Value(1)
//
//Expr.Value(1) = <@@1@@>
//
//


(* Async workflows sample (parallel CPU and I/O tasks) *)
 
(* A very naive prime number detector *)

let isPrime (n:int) =
    let bound = int (System.Math.Sqrt(float n))
    seq {2 .. bound} |> Seq.exists (fun x -> n % x = 0) |> not

let isprimeq =
     <@ 
        isPrime
     @>
 
(* We are using async workflows *)
let primeAsync n =
    async { return (n, isPrime n) }

let primeasyncq = <@ primeAsync @>
 
(* Return primes between m and n using multiple threads *)  
let primes m n =
    seq {m .. n}
        |> Seq.map primeAsync
        |> Async.Parallel
        |> Async.RunSynchronously
        |> Array.filter snd
        |> Array.map fst

let primesq = <@ primes @>
 
(* Run a test *)

//primes 1000000 1002000
//    |> Array.iter (printfn "%d")

let boffo = 
    <@
        primes 1000000 1002000
        |> Array.iter (printfn "%d") 
    @>

println isprimeq
println primeasyncq
println primesq
println boffo